/*
 * Copyright 2009 Pierre-Laurent Coirier
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.mvc4g.client;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * This class is in charged of forwarding event to action
 * 
 * It also contains a list of the view
 * 
 * @author plcoirier
 * 
 */
public class Controller {

	protected Controller parentController = null;
	protected Map<String, ActionInterface> actions = new HashMap<String, ActionInterface>();
	protected Map<String, ViewInterface> views = new HashMap<String, ViewInterface>();
	protected Map<String, Controller> childActions = new HashMap<String, Controller>();

	/**
	 * Handle an event by forwarding it to the right action
	 * 
	 * @param e
	 *            event to manage
	 * @throws Exception
	 *             exception thrown if action not manageable by the controller
	 */
	public void handleEvent(Event e) {
		String actionName = e.getActionName();
		if (actions.containsKey(actionName)) {
			actions.get(actionName).execute(this, e.getForm());
		} else if (childActions.containsKey(actionName)) {
			childActions.get(actionName).handleEvent(e);
		} else if (parentController != null) {
			parentController.handleEvent(e);
		} else {
			throw new Error("Action not manageable by this controller");
		}
	}

	/**
	 * Returns the view associated with the given name
	 * 
	 * @param viewName
	 *            name of the view you want to retrieve
	 * @return the view associated with the name
	 */
	public ViewInterface getView(String viewName) {
		return views.get(viewName);
	}

	/**
	 * Set a parent controller
	 * 
	 * This method can be called only after all actions have been added to the
	 * controller
	 * 
	 * @param parent
	 *            parent controller to set
	 */
	public void setParent(Controller parent) {
		parentController = parent;
		parentController.addChild(this, actions.keySet());
	}

	/**
	 * Add a view to the controller
	 * 
	 * @param viewName
	 *            name of the view
	 * @param view
	 *            view to add
	 */
	public void addView(String viewName, ViewInterface view) {
		views.put(viewName, view);
		view.setController(this);
	}

	/**
	 * Add an action to the controller
	 * 
	 * @param actionName
	 *            name of the action
	 * @param action
	 *            action to add
	 */
	public void addAction(String actionName, ActionInterface action) {
		actions.put(actionName, action);
	}

	/**
	 * Inform the controller of the actions that the child controller can manage
	 * 
	 * @param childController
	 *            child controller
	 * @param actionNameSet
	 *            set of action names it can manage
	 */
	private void addChild(Controller childController, Set<String> actionNameSet) {
		Iterator<String> it = actionNameSet.iterator();
		while (it.hasNext()) {
			childActions.put(it.next(), childController);
		}

		if (parentController != null) {
			parentController.addChild(this, actionNameSet);
		}
	}

}
